Manejo y visualización de datos

Importar, transformar y visualizar datos en R

Manejo de datos

La exploración de datos es el primer paso para:

  • Verificar su calidad
  • Comprender la información con la que trabajamos
  • Detectar errores o valores atípicos
  • Preparar los datos para su análisis o visualización

¿Qué es “tidy data”?

Un conjunto de datos está ordenado (tidy) cuando:

  • Cada variable tiene su propia columna
  • Cada observación tiene su propia fila
  • Cada valor tiene su propia celda

Ejemplo organización “tidy”

Buenas prácticas de sintaxis en R

Espacios y asignaciones

  • Usa espacios alrededor de los operadores
  • Usa <- en vez de =
  • Cuando haya funciones con el mismo nombre, especifica el paquete (dplyr::select ())
  • Empieza tu script con una descripción sobre lo que hace el código, autorx, fecha y sesión.

Organización de carpetas

  • Carpeta con los datos brutos

“carpetas”

Buenas prácticas en el manejo de datos

📋 Estructura y formato

  • Cada variable en una columna
  • Cada observación en una fila
  • No combines varias informaciones en una misma celda

🧩 Nombres y valores

  • Evita espacios, números o caracteres especiales en los nombres de columnas
  • Anota los ceros (0) cuando existen — no los dejes vacíos!!
  • Usa NA o celdas vacías para indicar datos faltantes
  • Separa las fechas en columnas: year, month, day

💾 Registro y reproducibilidad

  • Realiza todas las manipulaciones de datos mediante código, no manualmente
  • Así dejas rastro reproducible de cada cambio
  • Guarda o exporta tus datos en formatos de texto plano (.csv, .txt)
  • más universales, más fáciles de versionar con Git

Organizacion tabla

Hertz & McNeill 2024

Tidyverse

El universo ordenado.

El tidyverse es una colección de paquetes de R - Para hacer más fácil y coherente el trabajo con datos. - Todos comparten una filosofía común: - Filosofía: Los datos deben ser ordenados (tidy), el código legible y los resultados reproducibles

Código limpio

  • Comentarios útiles
  • Divide en pasos lógicos
  • Usa bien la sangría y los espacios
  • Usa bien los nombres
  • Guarda solo objetos útiles (R se va llenando)

Tips

  • control + shift + C (des)comenta todo a la vez
  • control + shift + A reformatea el código
  • control + click se abre la tabla en RStudio

Importar los datos

library(dplyr)
library(here)

glimpse(iris) # datos incluidos en dplyr
Rows: 150
Columns: 5
$ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
$ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
$ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
$ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
$ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
cobertura <- read.csv(here("data/cobertura.csv"))
glimpse(cobertura)
Rows: 200
Columns: 4
$ X         <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1…
$ biomasa   <dbl> 44.99793, 24.05575, 62.48798, 47.19165, 52.97670, 54.23581, …
$ cobertura <dbl> 18.559377, 24.147013, 68.896738, 30.016841, 31.254601, 38.79…
$ sequia    <chr> "seco", "seco", "seco", "seco", "seco", "seco", "seco", "sec…

Pipes: cómo encadenar operaciones

Los “pipes” permiten escribir código paso a paso, de forma legible:

library(dplyr)

# El propio de dplyr
iris %>%
  filter(Sepal.Length > 5) %>%
  summarise(promedio = mean(Sepal.Width))
  promedio
1 3.048305
# (control  (command) + shift + M)

# el de R desde hace unos años
iris |>
  filter(Sepal.Length > 5) |>
  summarise(promedio = mean(Sepal.Width))
  promedio
1 3.048305

Empecemos a manejar datos

Cosas importantes!

  • Primero pensar qué queremos hacer con los datos
  • El orden donde ponemos los argumentos
  • Si van dentro de paréntesis o no
  • dónde va la base de datos a la que hacemos referencia

Ejemplo datos de pingüinos

# 1. Cargar librerías

library(dplyr)
library(ggplot2)
library(readr)
library(palmerpenguins)
library(scico)

# 2. Leer datos
data(package = 'palmerpenguins')

# 3. Explorar
glimpse (penguins)
Rows: 344
Columns: 8
$ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
$ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
$ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
$ body_mass_g       <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
$ sex               <fct> male, female, female, NA, female, male, female, male…
$ year              <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…
unique(penguins$island)
[1] Torgersen Biscoe    Dream    
Levels: Biscoe Dream Torgersen
datos_filtrados <- penguins %>% filter (year == 2007)

datos_filtrados <- penguins %>% filter (year == 2007, sex == "female")

datos_filtrados <- penguins %>% filter (year == 2007, sex == "female", island %in% c("Dream", "Bicoe"))
# island == c("Dream", "Bicoe")) NO VALE!
# summarize
head (datos_filtrados, 3)
# A tibble: 3 × 8
  species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>           <dbl>         <dbl>             <int>       <int>
1 Adelie  Dream            39.5          16.7               178        3250
2 Adelie  Dream            39.5          17.8               188        3300
3 Adelie  Dream            36.4          17                 195        3325
# ℹ 2 more variables: sex <fct>, year <int>
penguins %>%
  filter(species == "Adelie") %>%
  summarise(promedio_pico = mean(bill_length_mm, na.rm = TRUE))
# A tibble: 1 × 1
  promedio_pico
          <dbl>
1          38.8

Limpiar los datos

# 4. Limpiar: eliminar filas con NA
datos_limpios <- penguins %>%
  filter(!is.na(body_mass_g))

head(datos_limpios, 4)
# A tibble: 4 × 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           39.1          18.7               181        3750
2 Adelie  Torgersen           39.5          17.4               186        3800
3 Adelie  Torgersen           40.3          18                 195        3250
4 Adelie  Torgersen           36.7          19.3               193        3450
# ℹ 2 more variables: sex <fct>, year <int>

Transformar variables

# 5. Transformar: crear nueva variable
datos_limpios_kg <- datos_limpios %>%
  mutate(body_mass_kg = body_mass_g / 1000)

Ejemplo datos inscripción curso

library(here)
library(tidyverse)
library(tm)
library(wordcloud2)
library(readxl)

# se puede importar tablas desde excel, csv, ggsheets, txt...

datos_curso = read_excel(here("data/datos-curso.xlsx"))
colnames(datos_curso) # Miramos las columnas que tiene
 [1] "Id"                                                                    
 [2] "Hora de inicio"                                                        
 [3] "Hora de finalización"                                                  
 [4] "Correo electrónico"                                                    
 [5] "Nombre"                                                                
 [6] "Comentarios: DNI o documento"                                          
 [7] "Curso de la primera matrícula en el programa de doctorado"             
 [8] "Puntos: Curso de la primera matrícula en el programa de doctorado"     
 [9] "Comentarios: Curso de la primera matrícula en el programa de doctorado"
[10] "Cuéntanos tu experiencia con R"                                        
[11] "Puntos: Cuéntanos tu experiencia con R"                                
[12] "Comentarios: Cuéntanos tu experiencia con R"                           
[13] "Observaciones"                                                         
[14] "Puntos: Observaciones"                                                 
[15] "Comentarios: Observaciones"                                            
datos_curso_filtrado <- datos_curso |>
  rename (
    curso = "Curso de la primera matrícula en el programa de doctorado",
    experiencia = "Cuéntanos tu experiencia con R",
    comentarios = "Observaciones",
    email = "Correo electrónico"
  ) |>
  select (curso, experiencia, comentarios, email) |>
  mutate (email = str_replace(email, "anonymous", "anónimo")) |>
  filter (curso == "2022-23") # filtrado y sin filtrar otra diapo.
  
words <- tolower(unlist(strsplit(datos_curso_filtrado$experiencia, " ")))

words <- gsub("[[:punct:][:digit:]]", "", words)
stop_es <- stopwords("spanish")
words_clean <- words[!words %in% stop_es]

# Plot
wordcloud2(
  data = table(words_clean),
  size = 0.5,
  color = rep(RColorBrewer::brewer.pal(11, "PRGn"), 20)
)

Ejercicios manejo de datos

Mismo ejercicio que ayer pero con dplyr.

Base de datos de flores: Por cada sitio y pantrap, tenemos el numero de flores que tienen las especies de plantas en Doñana. code = código de la planta

Ejercicio: Importa la base de datos “flores.csv” de la carpeta “data”, explora la base de datos, calcula la abundancia media de flores total, indica cuantas especies distintas hay de plantas. Luego, crea una base de datos con el número de individuos por especie (no de flores). Guardala como csv.

flores <- read.csv(here("data/flores.csv"))

# Estructura de los datos
glimpse(flores)
Rows: 490
Columns: 5
$ code      <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1…
$ site_id   <chr> "ANZ_1", "ANZ_1", "ANZ_1", "ANZ_1", "ANZ_1", "ANZ_1", "ANZ_1…
$ pantrap   <int> 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5, 5, 6, 7, 8, 8, 9, …
$ species   <chr> "Oxalis pes-caprae", "Cistus salvifolius", "Ornithogalum umb…
$ abundance <int> 3, 16, 4, 2, 3, 4, 1, 3, 1, 8, 2, 2, 1, 1, 2, 3, 12, 2, 6, 6…
# Promedio de abundancia
flores %>% 
  summarise (media_abundancia = mean(abundance, na.rm = TRUE))
  media_abundancia
1         16.45102
# Número de especies únicas
flores %>% 
  summarise (n_especies = n_distinct(species))
  n_especies
1         74
# Listado de especies únicas
flores %>% 
  distinct(species)
                    species
1         Oxalis pes-caprae
2        Cistus salvifolius
3   Ornithogalum umbellatum
4      Aristolochia baetica
5    Geranium rotundifolium
6  Aristolochia paucinervis
7           Reseda phyteuma
8            Ranunculus sp.
9           Anemone palmata
10           Cistus crispus
11           Cistus albidus
12       Erodium cicutarium
13       Lavandula stoechas
14                 Ulex sp.
15       Anagallis arvensis
16         Cistus ladanifer
17                       na
18   Rosmarinus officinalis
19               Crepis sp.
20       Xolantha tuberaria
21    Lupinus angustifolius
22          Linaria spartea
23     Centaurea calcitrapa
24       Misopates orontium
25       Halimium calycinum
26               Echium sp.
27          Senecio pequeño
28         Malcolmia lacera
29        Acis trichophylla
30            Leontodon sp.
31    Raphanus raphanistrum
32              Erodium sp.
33    Halimium halimifolium
34           Cerinthe major
35                Linum sp.
36                  Muscari
37                  Erodium
38      Echium plantagineum
39                Vicia sp.
40          Silene colorata
41        Sonchus oleraceus
42       Carduus bourgeanus
43              Senecio sp.
44         Dipcadi serotium
45   Leontodon longirostris
46            Arum italicum
47            Centaurea sp.
48          Genista hirsuta
49      Lysimachia arvensis
50              Carduus sp.
51          Lathyrus ochrus
52          Muscari romoani
53           Daphne gnidium
54  Convolvulus althaeoides
55    Parentucellia viscosa
56     Cistus monspeliensis
57   Bituminaria bituminosa
58           Tolpis barbata
59    Campanula matritensis
60         Cistus libanotis
61          Stellaria media
62     Galactites tomentosa
63        Anthemis arvensis
64                 Calycium
65    Andryala integrifolia
66        Gladius illyricus
67              Dipcadi sp.
68     Chrysantenum sesetum
69          Serapias lingua
70         Leopoldia comosa
71     Cynoglossum creticum
72       Bellardia trixiajo
73         Xolantha guttata
74          Thapsia villosa
# Conteo de registros por especie
flores %>% 
  count(species, sort = TRUE)
                    species   n
1        Cistus salvifolius 114
2        Xolantha tuberaria  44
3             Leontodon sp.  23
4           Anemone palmata  22
5           Silene colorata  20
6     Halimium halimifolium  12
7        Lavandula stoechas  12
8     Andryala integrifolia  11
9            Cistus albidus  11
10         Malcolmia lacera  11
11     Aristolochia baetica  10
12          Linaria spartea  10
13   Rosmarinus officinalis  10
14      Echium plantagineum   9
15              Erodium sp.   9
16     Galactites tomentosa   9
17       Halimium calycinum   9
18           Cistus crispus   8
19  Convolvulus althaeoides   8
20   Leontodon longirostris   7
21          Reseda phyteuma   7
22        Anthemis arvensis   6
23         Xolantha guttata   6
24               Crepis sp.   5
25          Genista hirsuta   5
26          Senecio pequeño   5
27        Acis trichophylla   4
28 Aristolochia paucinervis   4
29   Bituminaria bituminosa   4
30               Echium sp.   4
31       Erodium cicutarium   4
32        Oxalis pes-caprae   4
33     Centaurea calcitrapa   3
34     Chrysantenum sesetum   3
35         Cistus libanotis   3
36           Tolpis barbata   3
37              Carduus sp.   2
38         Cistus ladanifer   2
39     Cistus monspeliensis   2
40         Dipcadi serotium   2
41   Geranium rotundifolium   2
42                Linum sp.   2
43    Lupinus angustifolius   2
44      Lysimachia arvensis   2
45       Misopates orontium   2
46                  Muscari   2
47           Ranunculus sp.   2
48        Sonchus oleraceus   2
49                 Ulex sp.   2
50       Anagallis arvensis   1
51            Arum italicum   1
52       Bellardia trixiajo   1
53                 Calycium   1
54    Campanula matritensis   1
55       Carduus bourgeanus   1
56            Centaurea sp.   1
57           Cerinthe major   1
58     Cynoglossum creticum   1
59           Daphne gnidium   1
60              Dipcadi sp.   1
61                  Erodium   1
62        Gladius illyricus   1
63          Lathyrus ochrus   1
64         Leopoldia comosa   1
65          Muscari romoani   1
66  Ornithogalum umbellatum   1
67    Parentucellia viscosa   1
68    Raphanus raphanistrum   1
69              Senecio sp.   1
70          Serapias lingua   1
71          Stellaria media   1
72          Thapsia villosa   1
73                Vicia sp.   1
74                       na   1